package nl.hanze.web.homegrownrpc.generic;

import java.lang.reflect.*;
import java.io.*;
import java.util.*;
import java.util.jar.Pack200.Packer;

public class StubGenerator {
    private StringBuffer stbTemp;
    private String fullInterfaceName;
    private String nameStub;
    private String packageStub;
    private String locationStub;
    private HashMap<String, String> wrapperClass;

    public StubGenerator(String fullInterfaceName, String baseLocationStub) {
        this.fullInterfaceName=fullInterfaceName;
        this.nameStub=getInterfaceName()+"Stub";
        this.packageStub=getPackageName(false);
        this.locationStub=baseLocationStub+File.separatorChar+getPackageName(true);
        
        wrapperClass=new HashMap<String, String>();
        wrapperClass.put("boolean", "java.lang.Boolean");
        // Week 1 opdracht 4a
        wrapperClass.put("byte", "java.lang.Byte");
        wrapperClass.put("short", "java.lang.Short");
        wrapperClass.put("int", "java.lang.Integer");
        wrapperClass.put("long", "java.lang.Long");
        wrapperClass.put("float", "java.lang.Float");
        wrapperClass.put("double", "java.lang.Double");
        wrapperClass.put("char", "java.lang.Character");
    }

    public void generateStub() throws Exception {
        stbTemp=new StringBuffer();
        generatePackageName();
        generateEmptyLine();
        generateClassLine();
        Method[] methods=searchMethods();
        for(Method method : methods) {
            generateEmptyLine();
            generateMethod(method);
        }
        generateEmptyLine();
        generateLastLine();
        saveGeneratedClass();
    }

    private void generatePackageName() {
        if (packageStub!=null && packageStub.length()!=0) {
        	// week 1 opdracht 4c
        	stbTemp.append("package ");
        	stbTemp.append(packageStub);
        	stbTemp.append(";");
        }
    }

    private void generateClassLine() {
        stbTemp.append("public class ");
        stbTemp.append(nameStub);
        stbTemp.append(" extends nl.hanze.web.homegrownrpc.generic.Stub implements ");
        stbTemp.append(fullInterfaceName);
        // week 1 opdracht 4b
        stbTemp.append(" { ");
    }

    private Method[] searchMethods() throws Exception {
        // week 1 opdracht 4d
    	return Class.forName(this.fullInterfaceName).getDeclaredMethods();    	
    }

    private void generateMethod(Method method) {
        String returnType=method.getReturnType().getCanonicalName();
        boolean isPrimitive=wrapperClass.containsKey(returnType);
        boolean isVoid=returnType.equals("void");
        String methodName=method.getName();
        Class[] params=method.getParameterTypes();
        boolean hasParameters=params.length!=0;
        
        // week 1 opdracht 4e
        stbTemp.append("public ");
        stbTemp.append(returnType);
        stbTemp.append(" ");
        stbTemp.append(methodName);
        stbTemp.append("(");
        
        if(hasParameters){
        	for(int i = 0; i < params.length; i++) {
        		int j = i+1;
            	if(i > 0 && i < params.length){
            		stbTemp.append(", ");
            	}
            	Class c1 = params[i];
                stbTemp.append(c1.getName());
                stbTemp.append(" p");
                stbTemp.append(j);
            }
        }

        stbTemp.append(") throws Exception {");
        generateEmptyLine();
        stbTemp.append("throw new UnsupportedOperationException(\"Not supported yet.\");");
        generateEmptyLine();
        stbTemp.append("}");
        generateEmptyLine();
    }

    private void generateEmptyLine() {
        stbTemp.append("\n");
    }

    private void generateLastLine() {
        stbTemp.append("}\n");
    }

    private void saveGeneratedClass() throws Exception {
        File file=new File(locationStub);
        file.mkdirs();
        
        // Week 1 opdracht 4f
        file = new File(locationStub+File.separatorChar+nameStub+".java");
        BufferedWriter writer = new BufferedWriter(new FileWriter(file));
        writer.append(stbTemp);
        writer.close();
    }

    private String getInterfaceName() {
        int i=fullInterfaceName.lastIndexOf('.');
        if (i==-1) return fullInterfaceName;
        i++;
        return fullInterfaceName.substring(i);
    }

    private String getPackageName(boolean useSlashes) {
        int i=fullInterfaceName.lastIndexOf('.');
        if (i==-1) return "";
        if (useSlashes)
            return fullInterfaceName.substring(0,i).replace('.', File.separatorChar);
        else
            return fullInterfaceName.substring(0,i);
    }

    public static void main(String[] args) throws Exception {
        StubGenerator sg=new StubGenerator("nl.hanze.web.homegrownrpc.addressbook.AddressBook", "C:\\Temp");
        sg.generateStub();
    }

}
